package com.jalarbee.core.generic.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.jalarbee.core.generic.dao.DataAcessException;
import com.jalarbee.core.generic.dao.GenericDao;
import com.jalarbee.core.util.Chunk;

public class GenericDaoJpa<T, PK extends Serializable> implements
		GenericDao<T, PK> {

	private Class<T> type;
	@PersistenceContext
	private EntityManager entityManager;

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	public EntityManager getEntityManager() {
		return entityManager;
	}

	@SuppressWarnings("unchecked")
	public GenericDaoJpa() {
		type = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}

	public void create(Object newInstance) throws DataAcessException {
		try {
			entityManager.persist(newInstance);
		} catch (Exception e) {
			throw new DataAcessException(e);
		}
	}

	public void delete(Object persistentObject) throws DataAcessException {
		try {
			entityManager.remove(persistentObject);
		} catch (Exception e) {
			throw new DataAcessException(e);
		}

	}

	public T read(Serializable id) throws DataAcessException {
		try {
			return entityManager.find(type, id);
		} catch (Exception e) {
			throw new DataAcessException(e);
		}
	}

	public void update(Object transientObject) throws DataAcessException {
		try {
			entityManager.merge(transientObject);
		} catch (Exception e) {
			throw new DataAcessException(e);
		}

	}

	@SuppressWarnings("unchecked")
	public List<T> findAll(Chunk chunk) throws DataAcessException {
		StringBuffer buffer = new StringBuffer();
		buffer.append("FROM ");
		buffer.append(type.getSimpleName());
		buffer.append(" T");
		Query query = entityManager.createQuery(buffer.toString());
		if (chunk != null && chunk.makesSense()) {
			query.setFirstResult(chunk.getStart());
			query.setMaxResults(chunk.getSize() + chunk.getStart());
		}
		return query.getResultList();
	}
}
